using UnityEngine;
using HutongGames.PlayMaker;

using System;
using System.Collections.Generic;
using B83.ExpressionParser;

namespace HutongGames.PlayMaker.Actions
{

    [ActionCategory(ActionCategory.Math)]
    public class MathExpression : FsmStateAction
    {

        [RequiredField]
        [Tooltip("Math Expression, YOU MUST MAKE SURE THE CORRECTNESS YOURSELF.")]
        public FsmString _mathExpression;

        [RequiredField]
        [HideTypeFilter]
        [UIHint(UIHint.Variable)]
        public FsmVar _targetVariable;

        public override void OnEnter()
        {
            InitFsmVar();

            var parser = new ExpressionParser();
            var expr = parser.EvaluateExpression(_mathExpression.Value);

            AddParameters(_mathExpression.Value, expr, Fsm);

            if (null != _targetVariable)
            {
                if (!PlayMakerUtils.ApplyValueToFsmVar(Fsm, _targetVariable, expr.Value))
                {
                    Debug.LogErrorFormat("Apply expression value {0} to Target Variable {1} failed.",
                        expr.Value,
                        _targetVariable.variableName);
                }   
            }
            else
            {
                Debug.LogErrorFormat("{0}, Target Variable is null", Fsm.ActiveStateName);
            }

            Finish();
        }

        private void InitFsmVar()
        {
            
        }

        private void TestFunc()
        {
            foreach (var fsmVar in Fsm.Variables.FloatVariables)
            {
                Debug.LogFormat("{0}, {1}", fsmVar.Name, fsmVar.Value);
            }
        }

        private void AddParameters(string mathExpr, Expression expr, Fsm fsm)
        {
            for (int i = 0; i < fsm.Variables.FloatVariables.Length; i++)
            {
                var name = fsm.Variables.FloatVariables[i].Name;
                if (mathExpr.Contains(name))
                {
                    expr.Parameters[name].Value = Convert.ToDouble(fsm.Variables.FloatVariables[i].Value);
                }
            }

            for (int i = 0; i < fsm.Variables.IntVariables.Length; i++)
            {
                var name = fsm.Variables.IntVariables[i].Name;
                if (mathExpr.Contains(name))
                {
                    expr.Parameters[name].Value = Convert.ToDouble(fsm.Variables.IntVariables[i].Value);
                }
            }
        }

        public override string ErrorCheck()
        {
            try
            {
                var parse = new ExpressionParser();
                var expr = parse.EvaluateExpression(_mathExpression.Value);

                foreach (var paras in expr.Parameters)
                {
                    if (!FindParameters(Fsm, paras.Key))
                    {
                        return string.Format("The parameter {0} not exists in FSM {1}",
                            paras.Key, Fsm.Name);
                    }
                }
            }
            catch (Exception ex)
            {
                return string.Format("{0}: Math Expression Exception: {1}",
                    Fsm.Name, ex.ToString());
            }

            return string.Empty;
        }

        private bool FindParameters(Fsm fsm, string paraName)
        {
            for (int i = 0; i < fsm.Variables.FloatVariables.Length; i++)
            {
                var name = fsm.Variables.FloatVariables[i].Name;
                if (name.Equals(paraName))
                {
                    return true;
                }
            }

            for (int i = 0; i < fsm.Variables.IntVariables.Length; i++)
            {
                var name = fsm.Variables.IntVariables[i].Name;
                if (name.Equals(paraName))
                {
                    return true;
                }
            }

            return false;
        }

    }
}
